   // jquery  原生js封装的一个js库 (获取元素 操作元素 绑定事件)
    // 模拟jquery
    // 1. 练习构造函数的封装
    // 2. 预习jquery

    // html()
    // width()
    // hide()  show()

    // $.ajax() 

    function GetEle(selector) {  //接收一个字符串 作为选择器(css选择器)
        // {}
        // this -> {}

        this.eles = document.querySelectorAll(selector);


        // this.__proto__ = GetEle.prototype;
        // return this;

    }


    // html()   获取和设置html
    // html(123123)   有参数就设置
    // html()         没有参数就获取
    GetEle.prototype.html = function (con) {
        // this => 调用此方法的实例化对象   => 也可以使用each
        // arguments 实际参数的集合
        if (arguments.length >= 1) {  //有参数就设置

            this.each(function (i, ele) {
                ele.innerHTML = con;
            })
            return this;
            // for (var i = 0; i < this.eles.length; i++) {
            //     var ele = this.eles[i];
            //     ele.innerHTML = con;
            // }
        } else {  //没有参数就获取 (默认返回第一个)
            return this.eles[0].innerHTML;
        }
    }

    // text()   获取和设置text
    // text(123123)   有参数就设置
    // text()         没有参数就获取
    GetEle.prototype.text = function (con) {
        // this => 调用此方法的实例化对象
        // arguments 实际参数的集合
        if (arguments.length >= 1) {  //有参数就设置
            this.each(function (i, ele) {
                ele.innerText = con;
            })
            return this;
            // for (var i = 0; i < this.eles.length; i++) {
            //     var ele = this.eles[i];
            //     ele.innerText = con;
            // }
        } else {  //没有参数就获取 (默认返回第一个)
            return this.eles[0].innerText;
        }
    }

    // val()   获取和设置value值
    // val(123123)   有参数就设置
    // val()         没有参数就获取
    GetEle.prototype.val = function (con) {
        // this => 调用此方法的实例化对象
        // arguments 实际参数的集合
        if (arguments.length >= 1) {  //有参数就设置
            this.each(function (i, ele) {
                ele.innerText = con;
            })
            return this;
            // for (var i = 0; i < this.eles.length; i++) {
            //     var ele = this.eles[i];
            //     ele.value = con;
            // }
        } else {  //没有参数就获取 (默认返回第一个)
            return this.eles[0].value;
        }
    }

    GetEle.prototype.each = function (fn) {
        // this -> 调用此方法的实例化对象
        // 遍历的是 实例化对象中的集合 this.eles
        for (var i = 0; i < this.eles.length; i++) {
            var ele = this.eles[i];  //循环的当前原始数据
            var index = i;   // 循环的当前下标

            // 遍历 集合 每次循环时执行传入的回调函数
            // fn(ele, index);   //传统 forEach
            fn(index, ele);     // jquery中第一个是下标,第二个是当前元素
        }
        return this;
    }

    GetEle.prototype.hide = function () {
        //  this -> 调用此方法的实例化对象
        this.each(function (i, ele) {
            ele.style.display = "none";
        })
        return this;
    }
    GetEle.prototype.show = function () {
        //  this -> 调用此方法的实例化对象
        this.each(function (i, ele) {
            ele.style.display = "block";
        })
        return this;
    }
    GetEle.prototype.click = function (fn) {  // 接收传入的函数 => 点击时执行
        //  this -> 调用此方法的实例化对象
        this.each(function (i, ele) {
            // ele.onclick = function () {
            //     alert(1111);
            // }
            ele.onclick = fn;
        })
        return this;
    }
    // width()   // 获取和设置宽度
    // width("100px")
    // width()
    GetEle.prototype.width = function (con) {
        //  this -> 调用此方法的实例化对象
        if (arguments.length >= 1) {
            this.each(function (i, ele) {

                // con  
                // 100px 100pt 100% 100em 100rem 100vw 100vh 有单位  =>直接拼接
                // 100              => 没有单位默认拼接px

                var reg = /^\d+(px|pt|%|em|rem|vw|vh)$/;
                if (reg.test(con)) {   // 有单位  =>直接拼接
                    ele.style.width = con;
                } else {
                    ele.style.width = con + "px";
                }

            })
            return this;
        } else {
            // style只能获取内联样式   
            // return this.eles[0].style.width;

            // 获取非行内样式
            // return parseFloat(getStyle(this.eles[0], "width"));

            return parseFloat(this.getStyle("width"));
        }
    }

    GetEle.prototype.height = function (con) {
        //  this -> 调用此方法的实例化对象
        if (arguments.length >= 1) {
            this.each(function (i, ele) {

                // con  
                // 100px 100pt 100% 100em 100rem 100vw 100vh 有单位  =>直接拼接
                // 100              => 没有单位默认拼接px

                var reg = /^\d+(px|pt|%|em|rem|vw|vh)$/;
                if (reg.test(con)) {   // 有单位  =>直接拼接
                    ele.style.height = con;
                } else {
                    ele.style.height = con + "px";
                }

            })
            return this;
        } else {
            // style只能获取内联样式   
            // return this.eles[0].style.height;

            // 获取非行内样式
            // return parseFloat(getStyle(this.eles[0], "height"));

            return parseFloat(this.getStyle("height"));
        }
    }

    GetEle.prototype.getStyle = function (attr) {
        //  this -> 调用此方法的实例化对象  {eles:[]} 
        var ele = this.eles[0]; // 默认获取集合中的第一个
        try {
            return getComputedStyle(ele)[attr];
        } catch (err) {
            return ele.currentStyle[attr];
        }
    }
    // attr()  获取和设置  属性节点   Attribute
    // setAttribute(key,val)    attr(key,val)   两个参数就设置
    // getAttribute(key)        attr(key)       一个就获取

    GetEle.prototype.attr = function (key, val) {
        if (arguments.length >= 2) {   //两个参数就设置
            this.each(function (i, ele) {
                ele.setAttribute(key, val);
            })
            return this;
        } else {   //一个就获取
            return this.eles[0].getAttribute(key);
        }
    }

    GetEle.prototype.removeAttr = function (key) {
        this.each(function (i, ele) {
            ele.removeAttribute(key, val);
        })
        return this;
    }
    // prop()  获取和设置   元素节点的属性     property 属性
    // ele.className = 'newLi'   prop(key,val)   两个参数就设置
    // ele.className             prop(key)       一个就获取

    GetEle.prototype.prop = function (key, val) {
        if (arguments.length >= 2) {   //两个参数就设置
            this.each(function (i, ele) {
                ele[key] = val;
            })
            return this;
        } else {   //一个就获取
            return this.eles[0][key];
        }
    }

    GetEle.prototype.addClass = function () {
        if (arguments.length >= 1) {
            var _args = arguments;
            this.each(function (i, ele) {
                ele.classList.add(..._args);
            })
            return this;
        } else {
            var err = new Error("请传入至少一个class名!!");
            throw err;
        }
    }
    GetEle.prototype.removeClass = function () {
        if (arguments.length >= 1) {
            var _args = arguments;
            this.each(function (i, ele) {
                ele.classList.remove(..._args);
            })
            return this;
        } else {
            var err = new Error("请传入至少一个class名!!");
            throw err;
        }
    }

    // css()  获取和设置元素的css     property 属性
    // ele.style.width = '100px'     css(key,val)   两个参数就设置
    //                               css({width:"100px",height:"200px"})

    // getStyle("width")             css(key)       一个就获取
    GetEle.prototype.css = function (key, val) {
        if (arguments.length >= 2) {   //两个参数就设置
            this.each(function (i, ele) {
                ele.style[key] = val;
            })
            return this;
        } else {
            // 一个参数  判断是否是对象
            if (typeof arguments[0] === "object") {
                for (var k in arguments[0]) {
                    var v = arguments[0][k];
                    this.css(k, v);
                }
                return this;
            } else {  //不是对象 取值
                return this.getStyle(key);
            }
        }
    }

    // 链式操作
    // var arr = [];
    // arr.concat(1, 2).concat(3, 4).concat(5, 6);


    // eq(index)   返回对应下标的元素 (要求返回实例化对象)
    // $(".list li").eq(0).css("background", "red");   //  链式操作的本质   方法返回的也是同类型的实例化对象

    //  链式操作的本质   方法返回的也是同类型的实例化对象  return this => 返回值定死 但是操作的元素希望改变,只能手动改 this.eles 这个集合 


    GetEle.prototype.eq = function (index) {
        // this.eles[index] 原生dom元素
        // this  调用次方法的实例化对象    $(".list li").eq(0)  {eles:[li,li,li,li,li,li]}
        var ele = this.eles[index]; // 被选取的元素 (dom元素)   li 
        this.eles = [ele];  // 将被操作的元素放到集合中  覆盖之前的集合  {eles:[li]}

        return this;  // {eles:[li]}
    }

    // siblings()   返回除了被选中元素以外的所有同级元素
    // $(".list li").eq(0).css("background", "red").siblings().css("background","blue"); 
    GetEle.prototype.siblings = function (index) {
        var ele = this.eles[0]; // 被选中的元素   => 如果找到它的同级元素

        var parentEle = ele.parentElement; // 找到父元素
        var children = parentEle.children; // 通过父元素找到所有的子元素 (包含 ele)

        var list = []; // 被选中元素以外的所有同级元素
        for (var i = 0; i < children.length; i++) {
            var item = children[i];
            if (item !== ele) {
                list.push(item);
            }
        }

        this.eles = list;  // 被选中元素以外的所有同级元素的集合覆盖原本的集合

        return this;

    }


    function getStyle(ele, attr) {
        try {
            return getComputedStyle(ele)[attr];
        } catch (err) {
            return ele.currentStyle[attr];
        }
    }


    function $(selector) {   // 传一个css选择器 => 返回对应元素的实例化对象  
        return new GetEle(selector);
    }
